/***************************************************************************
 *   Copyright (C) 2007 by Warren Kenny   *
 *   warren.kenny@gmail.com   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "otaPacketCapture.h"

otaPacketCapture::otaPacketCapture()
{
}

void otaPacketCapture::listCaptureDevices()
{
#ifndef WIN32
	if( pcap_findalldevs(&m_deviceList, m_errorString) == -1 )
	{
		std::cout << "Failed to obtain a list of devices" << std::endl;
	}
#else
	if( pcap_findalldevs_ex( PCAP_SRC_IF_STRING, NULL, &m_deviceList, m_errorString) == -1 )
	{
		std::cout << "Failed to obtain a list of devices" << std::endl;
	}
#endif
	else
	{
		std::cout << "Compatible Capture Devices: " << std::endl << std::endl;
		while( m_deviceList->next != NULL)
		{
			std::cout << "Device Name: " << m_deviceList->name << std::endl;
			std::cout << "Device Description: ";
			if ( m_deviceList->description)
				std::cout << m_deviceList->description << std::endl;
			else            
				std::cout << "No description available" << std::endl;
			pcap_addr_t *IP_Att;
			for( IP_Att = m_deviceList->addresses; IP_Att; IP_Att = IP_Att->next )
			{
				std::cout << "Device Address List: " << std::endl << std::endl;
				if( IP_Att->addr->sa_family == AF_INET )
				{
					if (IP_Att->addr)
						std::cout << "    Address: " << inet_ntoa( ( ( struct sockaddr_in *) IP_Att->addr)->sin_addr ) << std::endl;
					if (IP_Att->netmask)
						std::cout << "    Netmask: " << inet_ntoa( ( ( struct sockaddr_in *) IP_Att->netmask )->sin_addr ) << std::endl;
					if (IP_Att->broadaddr)
						std::cout << "    Broadcast Address: " << inet_ntoa( ( ( struct sockaddr_in *) IP_Att->broadaddr )->sin_addr) << std::endl;
					if (IP_Att->dstaddr)
						std::cout << "    Destination Address: " << inet_ntoa( ( ( struct sockaddr_in *) IP_Att->dstaddr )->sin_addr ) << std::endl;
				}
			}
			m_deviceList = m_deviceList->next;			
		}
		std::cout << std::endl;
	}
}
	
	
bool otaPacketCapture::init( otaConfigReader& config )
{
	std::string serverPorts, captureDevice;
	if( config.getConfiguration( "MySQL Server Ports", serverPorts ) && config.getConfiguration( "Capture Device", captureDevice ) )
	{	
		return ( selectCaptureDevice( captureDevice ) && compileCaptureFilter( serverPorts ) );
	}
	return false;	
}
	
bool otaPacketCapture::selectCaptureDevice( std::string captureDevice )
{
	m_captureDevice = captureDevice;
	if( pcap_lookupnet( m_captureDevice.c_str() , &m_netMask, &m_localAddress, m_errorString) == -1 )
	{
		std::cout << "Error encountered while attempting to access device information: " << m_errorString << std::endl;
		listCaptureDevices();
		return false;
	}
	else
	{
		m_captureHandle = pcap_open_live( m_captureDevice.c_str() , BUFSIZ, 0, 1000, m_errorString);
		if( m_captureHandle == NULL )
		{
			std::cout << "Error encountered while attempting to obtain capture handle: " << m_errorString << std::endl;
			return false;
		}
		else
		{
			if( pcap_findalldevs(&m_deviceList, m_errorString) == -1 )
			{
				std::cout << "Unable to retrieve device information " << std::endl;
				return false;
			}
			else
			{
				bool devFound = false;
				while( m_deviceList->next != NULL && !devFound)
				{
					if( strcmp( m_deviceList->name, m_captureDevice.c_str() ) == 0)
					{
						pcap_addr_t *IP_Att;
						for( IP_Att = m_deviceList->addresses; IP_Att; IP_Att = IP_Att->next )
						{
							if(IP_Att->addr->sa_family == AF_INET && IP_Att->addr)
							{
								m_host = inet_ntoa(((struct sockaddr_in *)IP_Att->addr)->sin_addr);
								return true;
							}
						}
					}					
					m_deviceList = m_deviceList->next;			
				}
			}
			return false;
		}
	}	
}
	
bool otaPacketCapture::compileCaptureFilter( std::string captureFilter )
{
	std::string filter = "(port ";
	//std::string filter = "(not host " + m_host + ") && (port ";
	
	unsigned int offset = 0;
	
	std::string port = otaConfigReader::slice( captureFilter, ",", offset);
	while( port != "EOS" )
	{ 
		filter += port + " || port ";
		port = otaConfigReader::slice( captureFilter, ",", offset);
	}
	filter = filter.substr( 0, (filter.length() - 9) );
	filter += ")";

	strcpy( m_filter, filter.c_str() );
	if( pcap_compile( m_captureHandle, &m_compiledFilter, m_filter, 0, m_localAddress) == -1 ) 
		return false;
	else
	{
		if( pcap_setfilter(m_captureHandle, &m_compiledFilter) == -1) 
			return false;
		else
			return true;
	}
}
	
void otaPacketCapture::activateCapture( pcap_handler callbackFunction, u_char *arguments )
{
	pcap_loop( m_captureHandle, -1, callbackFunction, arguments);
}

otaPacketCapture::~otaPacketCapture()
{
}


